﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.IO;
using System.Threading;
using Aliyun.OSS.Common;
using Aliyun.OSS.Util;

namespace Aliyun.OSS.Sdk.JSST
{
    public class PutObject
    {
        private OssClient client = null;//new OssClient(Config.Endpoint, Config.AccessKeyId, Config.AccessKeySecret);

        private string fileToUpload = Config.FileToUpload;

        private AutoResetEvent _event = new AutoResetEvent(false);
        /// <summary>
        /// 静态构造
        /// 张睿 2017-11-09
        /// </summary>
        public PutObject()
        {
        }

        /// <summary>
        /// 环境变量改变
        /// 张睿 2017-11-09
        /// </summary>
        public void Ini()
        {
            LogOSS.Log.Info("收到‘环境变量改变通知’，执行‘重新初始化’");
            client = new OssClient(Config.Endpoint, Config.AccessKeyId, Config.AccessKeySecret);
        }

        /// <summary>
        /// put localFilePath to oss
        /// 张睿 2017-10-30
        /// </summary>
        /// <param name="key">（远程）对象名（即 文件名）</param>
        /// <param name="localFilePath">本地文件完整路径</param>
        /// <param name="resultMessage">返回信息</param>
        public int PutObjectFromFile(string key, string localFilePath, out Result resultMessage)
        {
            return PutObjectFromFile(Config.BucketName, key, localFilePath, out resultMessage);
        }

        /// <summary>
        /// put localFilePath to oss
        /// 张睿 2017-10-30
        /// </summary>
        /// <param name="bucketName">存储空间 名</param>
        /// <param name="key">（远程）对象名（即 文件名）</param>
        /// <param name="localFilePath">本地文件完整路径</param>
        /// <param name="resultMessage">返回信息</param>
        /// <returns>0:成功 1：失败 100：配置信息错误 101：其他异常</returns>
        public int PutObjectFromFile(string bucketName, string key, string localFilePath, out Result resultMessage)
        {
            int intResult = 1;
            resultMessage = new Result();
            resultMessage.Status = 1;

            //未初始化 不允许执行
            if (!Config.IsIni)
            {
                resultMessage.Message = "未初始化'平台账号信息' 拒绝执行, 请先调用 Config.Ini :(";
                resultMessage.Status = 100;
                intResult = 100;//参数未配置
            }
            //执行
            else
            {
                
                try
                {
                    PutObjectResult putObjectResult= client.PutObject(bucketName, key, localFilePath);
                    resultMessage.Message = JsonHelper.JsonSerialize<PutObjectResult>(putObjectResult);
                    if (putObjectResult.HttpStatusCode == System.Net.HttpStatusCode.OK)
                    {
                        resultMessage.Status = 0;
                        resultMessage.Message += ";" + GeneratePresignedUri(bucketName, key).ToString();
                        intResult = 0;
                    }
                    else
                    {
                        intResult = 1;
                        resultMessage.Status = 1;
                    }
                }
                catch (OssException ex)
                {
                    if (ex.ErrorCode == "SignatureDoesNotMatch" || ex.ErrorCode == "InvalidAccessKeyId")
                    {
                        resultMessage.FillOssException(ex);
                        resultMessage.Status = 100;
                        intResult = 100;
                    }
                    else
                    {
                        resultMessage.FillOssException(ex);
                        resultMessage.Status = 101;
                        intResult = 101;
                    }
                    //异常后重新初始化
                    this.Ini();

                }
                catch (Exception ex)
                {
                    resultMessage.Message = ex.Message;
                    resultMessage.Status = 101;
                    intResult = 101;
                    //异常后重新初始化
                    this.Ini();
                }

                #region 调试日志
                string rJson = "";
                try
                {
                    rJson = JsonHelper.JsonSerialize<Result>(resultMessage);
                }
                catch
                {
                    rJson = resultMessage.GetDefaultJsonStr();
                }
                //
                if (LogOSS.Log.IsDebugEnabled)
                {
                    string str = string.Format(@"PutObjectFromFile(bucketName={0}, key={1}, localFilePath={2}); 
return(json)返回值= {8}。
---- (原始)返回值 ---
result=Status:{3}。
error code: {4}; Error Message: {5}。
RequestID:{6},   HostID:{7}"
    , bucketName
    , key
    , localFilePath
    , resultMessage.Status
    , resultMessage.ErrorCode, resultMessage.Message, resultMessage.RequestId, resultMessage.HostId
    , rJson);

                    LogOSS.Log.Debug(str);
#if TEST
                    Console.WriteLine(str);
#endif

                }
                #endregion 调试日志
            }
            return intResult;
        }

        private void PutObjectFromString(string bucketName)
        {
            const string key = "PutObjectFromString";
            const string str = "Aliyun OSS SDK for C#";

            try
            {
                byte[] binaryData = Encoding.ASCII.GetBytes(str);
                var stream = new MemoryStream(binaryData);

                client.PutObject(bucketName, key, stream);
                Console.WriteLine("Put object:{0} succeeded", key);
            }
            catch (OssException ex)
            {
                Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                    ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed with error info: {0}", ex.Message);
            }
        }

        private void PutObjectWithDir(string bucketName)
        {
            const string key = "folder/sub_folder/PutObjectFromFile";

            try
            {
                client.PutObject(bucketName, key, fileToUpload);
                Console.WriteLine("Put object:{0} succeeded", key);
            }
            catch (OssException ex)
            {
                Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                    ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed with error info: {0}", ex.Message);
            }
        }

        private void PutObjectWithMd5(string bucketName)
        {
            const string key = "PutObjectWithMd5";

            string md5;
            using (var fs = File.Open(fileToUpload, FileMode.Open))
            {
                md5 = OssUtils.ComputeContentMd5(fs, fs.Length);
            }

            var meta = new ObjectMetadata() { ContentMd5 = md5 };
            try
            {
                client.PutObject(bucketName, key, fileToUpload, meta);

                Console.WriteLine("Put object:{0} succeeded", key);
            }
            catch (OssException ex)
            {
                Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                    ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed with error info: {0}", ex.Message);
            }
        }

        private void PutObjectWithHeader(string bucketName)
        {
            const string key = "PutObjectWithHeader";
            try
            {
                using (var content = File.Open(fileToUpload, FileMode.Open))
                {
                    var metadata = new ObjectMetadata();
                    metadata.ContentLength = content.Length;

                    metadata.UserMetadata.Add("github-account", "qiyuewuyi");

                    client.PutObject(bucketName, key, content, metadata);

                    Console.WriteLine("Put object:{0} succeeded", key);
                }
            }
            catch (OssException ex)
            {
                Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                    ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed with error info: {0}", ex.Message);
            }
        }

        private void AsyncPutObject(string bucketName)
        {
            const string key = "AsyncPutObject";
            try
            {
                // 1. put object to specified output stream
                using (var fs = File.Open(fileToUpload, FileMode.Open))
                {
                    var metadata = new ObjectMetadata();
                    metadata.UserMetadata.Add("mykey1", "myval1");
                    metadata.UserMetadata.Add("mykey2", "myval2");
                    metadata.CacheControl = "No-Cache";
                    metadata.ContentType = "text/html";

                    string result = "Notice user: put object finish";
                    client.BeginPutObject(bucketName, key, fs, metadata, PutObjectCallback, result.ToCharArray());

                    _event.WaitOne();
                }
            }
            catch (OssException ex)
            {
                Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                    ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed with error info: {0}", ex.Message);
            }
        }

        private void PutObjectCallback(IAsyncResult ar)
        {
            try
            {
                client.EndPutObject(ar);

                Console.WriteLine(ar.AsyncState as string);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            finally
            {
                _event.Set();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="bucketName"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public Uri GeneratePresignedUri(string bucketName, string key)
        {
            if (Config.IsIni == false)
            {
                return null;
            }

            Uri url = null;
            try
            {
                url = client.GeneratePresignedUri(Config.BucketName, key);
            }
            catch (Exception ex)
            {

                LogOSS.Log.Debug(ex.ToString());
            }

            return url;
            
        }
    }
}
